/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.icee.myth.server.channelHandler;

import com.google.gson.JsonSyntaxException;
import com.icee.myth.common.config.login.JSONLoginAuthData;
import com.icee.myth.common.config.login.JSONLoginAuthRetData;
import com.icee.myth.common.messageQueue.ServerMessageQueue;
import com.icee.myth.common.protobufmessage.ProtobufMessageType;
import com.icee.myth.log.GameLogger;
import com.icee.myth.log.message.FileDebugGameLogMessage;
import com.icee.myth.log.message.builder.GameLogMessageBuilder;
import com.icee.myth.protobuf.ExternalCommonProtocol.*;
import com.icee.myth.protobuf.builder.ClientToMapBuilder;
import com.icee.myth.server.GameServer;
import com.icee.myth.server.message.serverMessage.builder.MapMessageBuilder;
import com.icee.myth.utils.*;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBufferInputStream;
import org.jboss.netty.channel.*;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URL;
import java.nio.channels.ClosedChannelException;

/**
 * 玩家（Unity3d）连接处理
 * @author liuxianke
 */
//@ChannelPipelineCoverage("all")
public class PlayerConnectHandler extends SimpleChannelUpstreamHandler {

    public PlayerConnectHandler() {
    }

    @Override
    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
            throws Exception {
        // Add client channel connected message to message queue
        if (GameServer.INSTANCE.isShuttingDown()) {
            e.getChannel().close();
            return;
        }

        ServerMessageQueue.queue().offer(MapMessageBuilder.buildClientConnectMessage(e.getChannel()));
        GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_INFO,
                "Client connected channel id = " + e.getChannel().getId())); //TODO: remove this
    }

    @Override
    public void channelClosed(
            ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
        // Add client close message to messageQueue
        ServerMessageQueue.queue().offer(MapMessageBuilder.buildClientCloseMessage(e.getChannel()));
        GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_INFO,
                "Client closed channel id = " + e.getChannel().getId())); //TODO: remove this
    }

    @Override
    public void messageReceived(
            ChannelHandlerContext ctx, MessageEvent e) {
        // Add received messages to messageQueue
        if (GameServer.INSTANCE.isShuttingDown()) {
            e.getChannel().close();
            return;
        }

        try {
            ChannelBuffer cb = (ChannelBuffer) e.getMessage();
            short type = cb.readShort();
            short length = cb.readShort();

            // TODO: 可以优化为发channelId，MapServer中直接从channelId找到MapPlayer
            Integer playerId = GameServer.INSTANCE.channelID2PlayerIDMap.get(e.getChannel().getId());

            if ((playerId == null) && (type != ProtobufMessageType.C2S_LOGIN)) {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Handle wrong message[" + type + "] for unknown player, channel id[" + e.getChannel().getId() + "]"));
                return;
            }

            switch (type) {
                case ProtobufMessageType.C2S_LOGIN: {
                    if (playerId == null) {
                        LoginProto loginMsg = LoginProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                        String loginSession = loginMsg.getLoginsession();
                        if (loginSession == null) {
                            // 注册信息有错
                            loginFail(e.getChannel());
                            //e.getChannel().close();
                            return;
                        }

                        InetSocketAddress saddr = (InetSocketAddress) e.getChannel().getRemoteAddress();
                        InetAddress inetAddress = saddr.getAddress();
                        String clientIp = inetAddress.getHostAddress();
                        // 检测账号
                        JSONLoginAuthRetData loginAuthRetData = checkAccount(loginSession, clientIp);

                        if (loginAuthRetData == null || loginAuthRetData.result != 0 || loginAuthRetData.forbiddenendlogintime > (GameServer.INSTANCE.getCurrentTime() / Consts.MILSECOND_1SECOND)) {
                            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                    "Player[" + playerId + "] login fail for session[" + loginSession + "] result[" + loginAuthRetData.result + "]."));
                            
                            // TODO: 帐号认证不通过（是否需要通知客户端原因？）
                            loginFail(e.getChannel());
                            //e.getChannel().close();
                            return;
                        }

                        //login占位成功
                        // 产生登陆消息，并将登陆消息插入MessageQueue
                        ServerMessageQueue.queue().offer(MapMessageBuilder.buildLoginMessage(e.getChannel(), loginAuthRetData.id, loginAuthRetData.passport, loginAuthRetData.auth, loginAuthRetData.privilege, loginAuthRetData.forbiddenendtalktime));
                    } else {
                        GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                "Player[" + playerId + "] Can't multi-login."));
                    }
                    break;
                }
                case ProtobufMessageType.C2S_CREATECHAR: {
                    // 产生创建角色消息，并插入MessageQueue
                    CreateCharProto createCharInfo = CreateCharProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();

                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildCreateCharMessage(playerId, createCharInfo));
                    break;
                }
                case ProtobufMessageType.C2S_GUIDE_NEXT: {
                    IntValueProto intValueProto = IntValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildGuideNextMessage(playerId, intValueProto.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_STAGE_ENTER: {
                    EnterStageProto enterStageProto = EnterStageProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildEnterStageMessage(playerId, enterStageProto.getStageId(), enterStageProto.getIsBigStage(), enterStageProto.getHelper()));
                    break;
                }
                case ProtobufMessageType.C2S_STAGE_CONTINUE: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildStageContinueMessage(playerId));
                    break;
                }
                case ProtobufMessageType.C2S_STAGE_LEAVE: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildLeaveStageMessage(playerId));
                    break;
                }
                case ProtobufMessageType.C2S_STARTPVEBATTLE: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildStartPveBattleMessage(playerId));
                    break;
                }
                case ProtobufMessageType.C2S_STAGE_REVIVE: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildStageReviveMessage(playerId));
                    break;
                }
                case ProtobufMessageType.C2S_CARD_STRENGTHEN: {
                    CardFoodsProto cardFoodsProto = CardFoodsProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildCardStrengthenMessage(playerId, cardFoodsProto.getCardInstId(), cardFoodsProto.getFoodCardInstIdsList()));
                    break;
                }
                case ProtobufMessageType.C2S_CARD_TRANSFORM: {
                    CardFoodsProto cardFoodsProto = CardFoodsProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildCardTransformMessage(playerId, cardFoodsProto.getCardInstId(), cardFoodsProto.getFoodCardInstIdsList()));
                    break;
                }
                case ProtobufMessageType.C2S_CARD_SOLD: {
                    IntValuesProto intValuesProto = IntValuesProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildCardSoldMessage(playerId, intValuesProto));
                    break;
                }
                case ProtobufMessageType.C2S_CARD_DRAW: {
                    VariableValueProto variableValueProto = VariableValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildCardDrawMessage(playerId, variableValueProto.getId(), (int)variableValueProto.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_MAIL_GET_LIST: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildGetMailListMessage(playerId));
                    break;
                }
                case ProtobufMessageType.C2S_MAIL_GET_INFO: {
                    LongValueProto longValue = LongValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildGetMailInfoMessage(playerId, longValue.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_MAIL_GET_REWARD: {
                    LongValueProto longValue = LongValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildGetMailRewardMessage(playerId, longValue.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_MAIL_REMOVE: {
                    LongValueProto longValue = LongValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildRemoveMailMessage(playerId, longValue.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_QUEST_SUBMIT: {
                    IntValueProto intValueProto = IntValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildQuestSubmitMessage(playerId, intValueProto.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_TALK: {
                    C2STalkProto c2STalkProto = C2STalkProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildTalkMessage(playerId, c2STalkProto));
                    break;
                }
                case ProtobufMessageType.C2S_CONTSIGN_RECEIVE_CUMULATIVE_SIGN_REWARD: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildContSignReceiveCumulativeSignRewardMessage(playerId));
                    break;
                }
                case ProtobufMessageType.C2S_CONTSIGN_RECEIVE_CONSECUTIVE_SIGN_REWARD: {
                    IntValueProto intValue = IntValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildContSignReceiveConsecutiveSignRewardMessage(playerId, intValue.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_CONTSIGN_RECEIVE_LIVENESS_REWARD: {
                    IntValueProto intValue = IntValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildContSignReceiveLivenessRewardMessage(playerId, intValue.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_VIPGIFT_RECEIVE: {
                    IntValueProto intValue = IntValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildVipGiftReceiveMessage(playerId, intValue.getValue()));
                    break; 
                }
                case ProtobufMessageType.C2S_SANDBOX_DEPLOY: {
                    SandboxProto sandBoxProto = SandboxProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildSandBoxDeployMessage(playerId, sandBoxProto));
                    break;
                }
                case ProtobufMessageType.C2S_HEGEMONY_ONE_TOKEN_FIGHT: {
                    IntValueProto intValue = IntValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildHegemonyOneTokenFightMessage(playerId, intValue.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_HEGEMONY_THREE_TOKEN_FIGHT: {
                    IntValueProto intValue = IntValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildHegemonyThreeTokenFightMessage(playerId, intValue.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_HEGEMONY_REFRESH: {
                    IntValueProto intValue = IntValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildHegemonyRefreshMessage(playerId, intValue.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_HEGEMONY_GET_PAY: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildHegemonyGetPayMessage(playerId));
                    break;
                }
                case ProtobufMessageType.C2S_SOCIAL_ADD_CONCERN: {
                    IntValueProto intValue = IntValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildSocialAddConcernMessage(playerId, intValue.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_SOCIAL_REMOVE_CONCERN: {
                    IntValueProto intValue = IntValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildSocialRemoveConcernMessage(playerId, intValue.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_SOCIAL_OTHERPLAYERINFO: {
                    IntValueProto intValue = IntValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildLookOtherPlayerInfoMessage(playerId, intValue.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_SOCIAL_CONCERN_NOTE: {
                    IntValueProto intValue = IntValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildSocialConcernNoteMessage(playerId, intValue.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_BUY_ENERGY: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildBuyEnergyMessage(playerId));
                    break;
                }
                case ProtobufMessageType.C2S_BUY_TOKEN: {
                    IntValueProto intValue = IntValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildBuyTokenMessage(playerId, intValue.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_ITEM_COMBINE: {
                    IntValueProto intValue = IntValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildItemCombineMessage(playerId, intValue.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_GET_BILL: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildGetBillMessage(playerId));
                    break;
                }
                case ProtobufMessageType.C2S_GET_COUPON: {
                    StringValueProto stringValue = StringValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildGetCouponMessage(playerId, stringValue.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_NORMAL_ACTIVITY_GET_LIST: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildNormalActivityGetListMessage(playerId));
                    break;
                }
                case ProtobufMessageType.C2S_NORMAL_ACTIVITY_GET_ITEM_LIST: {
                    IntValueProto intValueProto = IntValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildNormalActivityGetItemListMessage(playerId, intValueProto.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_NORMAL_ACTIVITY_ENTER_STAGE: {
                    EnterActivityStageProto enterActivityStageProto = EnterActivityStageProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildEnterActivityStageMessage(playerId, enterActivityStageProto.getActivityId(), enterActivityStageProto.getItemId(), enterActivityStageProto.getHelperId()));
                    break;
                }
                case ProtobufMessageType.C2S_NORMAL_ACTIVITY_GET_REWARD: {
                    VariableValueProto variableValueProto = VariableValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildGetNormalActivityRewardMessage(playerId, variableValueProto.getId(), (int)variableValueProto.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_CARD_DRAW_ACTIVITY_GET_LIST: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildCardDrawActivityGetListMessage(playerId));
                    break;
                }
                case ProtobufMessageType.C2S_STAGE_ACTIVITY_GET_LIST: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildStageActivityGetListMessage(playerId));
                    break;
                }
                case ProtobufMessageType.C2S_BASE_BARRACK_DEPLOY: {
                    IntValuesProto intValuesProto = IntValuesProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildBarrackDeployMessage(playerId, intValuesProto));
                    break;
                }
                case ProtobufMessageType.C2S_BASE_ORDNANCE_DEPLOY: {
                    IntValuesProto intValuesProto = IntValuesProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildOrdnanceDeployMessage(playerId, intValuesProto));
                    break;
                }
                case ProtobufMessageType.C2S_BASE_COUNCIL_DEPLOY: {
                    IntValuesProto intValuesProto = IntValuesProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildCouncilDeployMessage(playerId, intValuesProto));
                    break;
                }
                case ProtobufMessageType.C2S_BASE_TRAINING_DEPLOY: {
                    IntValuesProto intValuesProto = IntValuesProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildBaseTrainingDeployMessage(playerId, intValuesProto));
                    break;
                }
                case ProtobufMessageType.C2S_BASE_MINE_DEPLOY: {
                    IntValuesProto intValuesProto = IntValuesProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildMineDeployMessage(playerId, intValuesProto));
                    break;
                }
                case ProtobufMessageType.C2S_BASE_GET_MINE_INCOME_INFO: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildBaseGetMineIncomeInfoMessage(playerId));
                    break;
                }
                case ProtobufMessageType.C2S_BASE_HARVEST_SELF_MINE_INCOME: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildBaseHarvestSelfMineIncomeMessage(playerId));
                    break;
                }
                case ProtobufMessageType.C2S_BASE_HARVEST_CAPE_MINE_INCOME: {
                    IntValueProto intValueProto = IntValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildBaseHarvestCapeMineIncomeMessage(playerId, intValueProto.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_BASE_GET_OCCUPY_INFO: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildBaseGetOccupyInfoMessage(playerId));
                    break;
                }
                case ProtobufMessageType.C2S_BASE_GET_TARGETS: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildBaseGetTargetsMessage(playerId));
                    break;
                }
                case ProtobufMessageType.C2S_BASE_ATTACK: {
                    VariableValueProto variableValueProto = VariableValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildBaseAttackMessage(playerId, variableValueProto.getId(), (int) variableValueProto.getValue()));
                    break;
                }
                case ProtobufMessageType.C2S_BASE_ONE_TOKEN_RESISTANCE: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildBaseResistanceMessage(playerId, false));
                    break;
                }
                case ProtobufMessageType.C2S_BASE_THREE_TOKEN_RESISTANCE: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildBaseResistanceMessage(playerId, true));
                    break;
                }

                // GM相关
                case ProtobufMessageType.C2S_GM_ADD_ENERGY: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildGMAddEnergyMessage(playerId));
                    break;
                }
                case ProtobufMessageType.C2S_GM_IGNORE_GUIDE_STEP: {
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildGMIgnoreGuideStepMessage(playerId));
                    break;
                }
                case ProtobufMessageType.C2S_GM_ADD_GOLDEN: {
                    IntValueProto intValueProto = IntValueProto.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildGMAddGoldenMessage(playerId, intValueProto.getValue()));
                }
                // TODO: 删除GM调试消息
//                case ProtobufMessageType.C2S_DEBUG_GM: {
//                    C2S_GM gmMessage = C2S_GM.getDefaultInstance().newBuilderForType().mergeFrom(new ChannelBufferInputStream(cb)).build();
//                    ServerMessageQueue.queue().offer(MapMessageBuilder.buildGMMessage(playerId, gmMessage));
//                    break;
//                }
                // TODO: 处理其他玩家来的消息
            }
        } catch (IOException ex) {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileNetErrorGameLogMessage(StackTraceUtil.getStackTrace(ex)));
            e.getChannel().close();
        }
    }

    @Override
    public void exceptionCaught(
            ChannelHandlerContext ctx, ExceptionEvent e) {
        if (!(e.getCause() instanceof ClosedChannelException)) {
            //GameLogger.getlogger().log(LogConsts.LOGTYPE_NETERR, StackTraceUtil.getStackTrace(e.getCause()));
            // TODO: 客户端异常，是否需要关闭与Client的连接？
            e.getChannel().close();
        }
    }

    private JSONLoginAuthRetData checkAccount(String sessionId, String clientIp) {
        HttpURLConnection con = null;
        BufferedReader in = null;
        BufferedOutputStream bos = null;
        try {
            System.out.println("loginCheckAddress="+GameServer.INSTANCE.loginCheckAddress);
            con = (HttpURLConnection) new URL(GameServer.INSTANCE.loginCheckAddress).openConnection();
            con.setRequestMethod("POST");
            con.setDoOutput(true);
            con.setConnectTimeout(2000);
            con.setReadTimeout(2000);

            //Http请求
            JSONLoginAuthData data = new JSONLoginAuthData();
            data.sessionId = sessionId;
            data.clientIp = clientIp;

            bos = new BufferedOutputStream(con.getOutputStream());
            bos.write(JSONHelper.toJSON(data).getBytes("UTF-8"));
            bos.flush();

            //获取结果
            in = new BufferedReader(new InputStreamReader(con.getInputStream()));
            String ret = in.readLine();

            JSONLoginAuthRetData retData = null;
            try {
                System.out.println("ret="+ret);
                retData = JSONHelper.parseString(ret, JSONLoginAuthRetData.class);
            } catch (JsonSyntaxException jse) {
                // 记录JSON parse出错
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "JSON parse error in PlayerConnectHandler.checkAccount()."));
                return null;
            }

            return retData;
        } catch (IOException ex) {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileNetErrorGameLogMessage(StackTraceUtil.getStackTrace(ex)));
            return null;
        } finally {
            //关闭连接，原则：先打开的后关闭。
            if (in != null) {
                try {
                    in.close();
                } catch (IOException ex) {
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileNetErrorGameLogMessage(StackTraceUtil.getStackTrace(ex)));
                }
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException ex) {
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileNetErrorGameLogMessage(StackTraceUtil.getStackTrace(ex)));
                }
            }
            if (con != null) {
                con.disconnect();
            }
        }
    }

    private void loginFail(final Channel channel) {
        if (channel == null) {
            return;
        }

        ChannelFuture f = channel.write(ClientToMapBuilder.buildLoginFail());
        if (f != null) {
            f.addListener(new ChannelFutureListener() {

                @Override
                public void operationComplete(ChannelFuture future) {
                    future.getChannel().close();
                }
            });
        }
    }

    public static void main(String[] args) throws EncryptException, IOException, ClassNotFoundException {
        String text = "aabbccddeeffgg";

//        AESUtil.generateKey("e:/masterkey");
        String etext = AESUtil.encryptToString(AESKey.key, text);
        System.out.println(etext);

        String dtext = AESUtil.decryptToString(AESKey.key, etext);
        System.out.println(dtext);

        /*
        String pass = "123456789";
        ByteString epasswd = ByteString.copyFrom(RSAUtil.encrypt(RSAKey.pubKey, pass.getBytes()));
        
        long startTime = System.currentTimeMillis();
        for(int i=0; i<10; i++) {
        RSAUtil.decrypt(RSAKey.priKey, epasswd.toByteArray());
        }
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - startTime);
         * 
         */

        /*
        ClientToLGWHandler testHandler = new ClientToLGWHandler();
        System.out.println(testHandler.checkAccount("陈诚", "123456"));
        System.out.println(testHandler.registerToOccupyService(4, "play"));
         *
         */
    }
}
